﻿using SPWebShell.entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Text;
using System.Web.Services.Protocols;

namespace SPWebShell.cmdlet
{
    /// <summary>
    /// Retrieves information about the specified List or document library
    /// </summary>
    [Cmdlet(VerbsCommon.Get, "SPList")]
    public class GetSPListCmdLet : CmdLetBase
    {

        private bool allfields;
        public GetSPListCmdLet()
        {

        }
        [Parameter(Mandatory = true, HelpMessage = "The title of the List")]
        [ValidateNotNullOrEmpty]
        public string List { get; set; }
        
        [Parameter(Mandatory = true, HelpMessage="The absolute URL to the web site where the List is located or any item/view within the List. e.g. http://server/sites/SiteA/doclib1/Allitems.aspx")]
        [ValidateNotNullOrEmpty]
        public string Url { get; set; }
        
        [Parameter(Mandatory = false, HelpMessage = "When set to True the complete List schema XML will be saved to a file")]
        public SwitchParameter Dump { get; set; }

        [Parameter(Mandatory = false, HelpMessage = "The name of the file where the List schema will be optionally written to when Dump=True")]
        public string File { get; set; }

        [Parameter(Mandatory = false, HelpMessage = "A comma separated list of fields to display in the output. Use the Dump option to view all fields in the XML. ID, ItemCount,EnableVersioning")]
        [Alias("Property")]
        public string[] Properties { get; set; }

        protected override void ProcessRecord()
        {
            try
            {
                WriteVerbose("Start time: " + DateTime.Now.ToString());
                ISPRepository repos = base.SPRepos;
                SPDoclibLocation location = repos.ResolveDoclibUrlFromPageUrl(this.Url);
                //If a List name has been provided then use this name
                if (!string.IsNullOrEmpty(this.List)) location.DoclibName = this.List;
                SPList listinfo = repos.GetList(location);
                //base.WriteObject(listinfo);
                string fullPathFile = "";
                if (this.Dump)
                {
                    VerboseLogger("Dump=true");
                    if (string.IsNullOrEmpty(File))
                    {
                        throw new Exception("Expected path to file (property File) where the list schema will be saved. ");
                    }
                    else
                    {
                        fullPathFile= this.GetFullPathToFile(this.File);
                        VerboseLogger("Full path to file:" + fullPathFile);
                        System.IO.File.WriteAllText(fullPathFile, listinfo.ToString());
                        VerboseLogger(string.Format("Contents of the XML was written to file:{0}", this.File));
                    }
                }
                PSObject o1 = new PSObject();
                List<string> fieldsToDisplay = new List<string>();
                //fieldsToDisplay.AddRange(new string[] { "ID", "ItemCount", "EnableVersioning" });
                //
                //Add the user specified columns only if the user has specified 1 or more custom fields
                //
                if ((this.Properties != null) && (this.Properties.Length > 0))
                {
                    this.PurifyAndAddUserFields(fieldsToDisplay, listinfo);
                }
                else
                {
                    this.AddAllFields(fieldsToDisplay, listinfo);
                }
                fieldsToDisplay.Sort();
                foreach (string fieldName in fieldsToDisplay)
                {
                    string fieldValue = listinfo.NameValues[fieldName];
                    o1.Members.Add(new PSNoteProperty(fieldName, fieldValue));
                }
                ///
                /// If user wants to display all schema fields then add to output
                ///
                if (this.AllFields)
                {
                    o1.Members.Add(new PSNoteProperty("Fields", listinfo.Fields.ToArray()));

                }
                WriteObject(o1);
                var qry = from f in listinfo.Fields orderby f.DisplayName select f;
                foreach (SPField field in qry.ToArray())
                {
                    WriteVerbose(string.Format("{0}\t\t{1}\t\t{2}", field.DisplayName, field.InternalName,field.Type));
                }
                base.ProcessRecord();
            }
            catch (SoapException ex)
            {
                string message = ex.Detail.OuterXml;
                throw new Exception(message, ex);
            }
            finally
            {
                WriteVerbose("End time: " + DateTime.Now.ToString());
            }
        }
        /// <summary>
        /// Add all fields in the List schema into the List<>
        /// </summary>
        /// <param name="fieldsToDisplay"></param>
        /// <param name="listinfo"></param>
        private void AddAllFields(List<string> fieldsToDisplay, SPList listinfo)
        {
            string[] allkeys = listinfo.NameValues.Keys.ToArray();
            fieldsToDisplay.AddRange(allkeys);
        }
        /// <summary>
        /// Adds all user specified List property fields to the collection - but only after taking into consideration the case.
        /// </summary>
        /// <param name="fieldsToDisplay"></param>
        private void PurifyAndAddUserFields(List<string> fieldsToDisplay, SPList listinfo)
        {
            if (this.Properties == null) return;
            string[] allkeys = listinfo.NameValues.Keys.ToArray();
            foreach (string userspecifiedfield in this.Properties)
            {
                if (string.IsNullOrEmpty(userspecifiedfield)) continue;
                string userspecifiedfieldTrimmed = userspecifiedfield.Trim();
                string keypropercase = allkeys.FirstOrDefault(k => (k.Equals(userspecifiedfieldTrimmed, StringComparison.CurrentCultureIgnoreCase)));
                if (string.IsNullOrEmpty(keypropercase))
                {
                    ErrorLogger("Field not found:" + userspecifiedfield);
                }
                else
                {
                    fieldsToDisplay.Add(keypropercase);
                }
            }
        }
        /// <summary>
        /// When specified all fields will be displayed in the output
        /// </summary>
        [Parameter(Mandatory = false, HelpMessage = "When specified all fields in the List schema will be displayed in the output")]
        [Alias("fields")]
        public SwitchParameter AllFields 
        { 
            get
            {
                return allfields;
            }
            set
            {
                allfields = value;
            }
        }
    }
}
